//状态监测
var stats = new Stats();
var sds = stats.domElement.style;
sds.position = 'absolute';
sds.top = '0px';
sds.right = '0px';
document.body.appendChild(stats.domElement);

function Vector(x, y) {
    this.x = x || 0;
    this.y = y || 0;
}
Vector.random = function() {
    return new Vector(
        Math.random() * 2 - 1,
        Math.random() * 2 - 1
    )
}
Vector.add = function(a, b) {
    return new Vector(a.x + b.x, a.y + b.y);
}
Vector.sub = function(a, b) {
    return new Vector(a.x - b.x, a.y - b.y);
}
Vector.scale = function(v, s) {
    return v.close().scale(s);
}
Vector.prototype = {
    set: function(x, y) {
        if(typeof x === 'object') {
            y = x.y;
            x = x.x;
        }
        this.x = x || 0;
        this.y = y || 0;
        return this;
    },
    add: function(v) {
        this.x += v.x;
        this.y += v.y;
        return this;
    },
    sub: function(v) {
        this.x -= v.x;
        this.y -= v.y;
        return this;
    },
    scale: function(sx, sy) {
        this.x *= sx;
        this.y = sy ? this.y * sy : this.y * sx;
        return this;
    },
    length: function() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    },
    distanceTo: function(v) {
        var dx = v.x - this.x,
            dy = v.y - this.y;
        return Math.sqrt(dx * dx + dy * dy);
    },
    angle: function() {
        return Math.atan2(this.y, this.x);
    },
    angleTo: function(v) {
        var dx = v.x - this.x,
            dy = v.y - this.y;
        return Math.atan2(dy, dx);
    },
    normalize: function() {
        var m = Math.sqrt(this.x * this.x + this.y * this.y);
        if(m) {
            this.x /= m;
            this.y /= m;
        }
        return this;
    },
    clone: function() {
        return new Vector(this.x, this.y);
    }
}

/**
 * 星点构造函数
 * @param {Nunber} x 星点横坐标
 * @param {Number} y 星点纵坐标
 * @param {Number} r 星点半径
 */
function Star(x, y, r) {
    Vector.call(this, x, y);
    this.radius = r;
    this._speed = new Vector();
}
Star.bounce = -1; //反弹系数
Star.stars = [];
Star.area = 100; //探测范围
Star.prototype = (function(o){
    var s = new Vector(), p;
    for(p in o) s[p] = o[p];
    return s;
})({
    update: function(ctxStar, ctxLine, cCircle) {
        this.add(this._speed);
        this.draw(ctxStar);
        this.drawLine(ctxLine, cCircle);
    },
    draw: function(ctx) {
        var i, j, s1, s2;
        ctx.save();
        ctx.fillStyle = ctx.strokeStyle = 'rgba(255, 255, 255, .5)';
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
        ctx.closePath();
        ctx.fill();
    },
    drawLine: function(ctx, cCircle) {
        var stars = [], i, s, j;
        for(j = 0; j < Star.stars.length; j += 1) {
            if(Star.stars[j].distanceTo(cCircle) < cCircle.radius) {
                stars.push(Star.stars[j]);
            }
        }
        ctx.save();
        ctx.lineWidth = .3;
        ctx.strokeStyle = 'rgba(255, 255, 255, .3)';
        ctx.beginPath();
        for(i = 0; i < stars.length; i += 1) {
            s = stars[i];
            if(s.distanceTo(this) < Star.area) {
                ctx.moveTo(s.x, s.y);
                ctx.lineTo(this.x, this.y);
            }
        }
        ctx.stroke();
        ctx.restore();
    }
});

/**
 * 控制圆类
 */
function ControlCircle(x, y, r) {
    Vector.call(this, x, y);
    this.radius = r;
}
ControlCircle.prototype = (function(o){
    var s = new Vector(), p;
    for(p in o) s[p] = o[p];
    return s;
})({
    draw: function(ctx) {
        ctx.save();
        ctx.strokeStyle = 'rgba(255, 255, 255, 0)';
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
        ctx.closePath();
        ctx.stroke();
        ctx.restore();
    }
});

//初始化
(function(){
    var canvas = document.getElementById('c'),
        context = canvas.getContext('2d'),
        bufferCvs = document.createElement('canvas'),
        bufferCtx = bufferCvs.getContext('2d'),
        screenWidth, screenHeight,
        count = 120, mouse = new Vector(), cCircle = new ControlCircle(0, 0, 150),
        stars = [];

    //初始化群星
    function initStars(count) {
        for(var i = 0; i < count; i += 1) {
            var s = new Star(
                Math.random() * screenWidth + 1,
                Math.random() * screenHeight + 1,
                Math.random() * 3 + 1,
            );
            s._speed.set(Vector.random());
            Star.stars.push(s);
        }
        stars = Star.stars;
    }

    //窗口resize事件处理函数
    function handleResize() {
        screenWidth = canvas.width = window.innerWidth;
        screenHeight = canvas.height = window.innerHeight;
        bufferCvs.width = screenWidth;
        bufferCvs.height = screenHeight;
    }

    //鼠标移动事件处理函数
    function handleMouseMove(e) {
        var event = e || window.event;
        mouse.set(e.clientX, e.clientY);
        cCircle.set(mouse);
    }

    //事件绑定
    window.addEventListener('resize', handleResize, false);
    canvas.addEventListener('mousemove', handleMouseMove, false);
    handleResize();
    initStars(count);

    //动画函数
    function animate() {
        var i, s;
        //绘制背景
        context.save();
        context.fillStyle = 'rgb(23, 23, 23)';
        context.fillRect(0, 0, canvas.width, canvas.height);
        context.restore();

        bufferCtx.save();
        bufferCtx.globalCompositeOperation = 'destination-out';
        bufferCtx.fillRect(0, 0, screenWidth, screenHeight);
        bufferCtx.restore();

        cCircle.draw(bufferCtx);

        for(i = 0; i < stars.length; i += 1) {
            s = stars[i];
            //触边检查
            if(s.x + s.radius > canvas.width || s.x - s.radius < 0) {
                //触右边、左边
                s._speed.scale(Star.bounce, 1);
            } else if (s.y - s.radius < 0 || s.y + s.radius > canvas.height) {
                //触上边、下边
                s._speed.scale(1, Star.bounce);
            }
            s.update(context, bufferCtx, cCircle);
        }

        context.drawImage(bufferCvs, 0, 0);
        requestAnimationFrame(animate);

        stats.update();
    }

    animate();
})()